package com.chinda.common.security;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import com.chinda.common.constants.CommonConstant;
import com.chinda.modules.sys.entity.SysMenuEntity;
import com.chinda.modules.sys.service.SysConfigService;
import com.chinda.modules.sys.service.SysMenuService;
import lombok.AllArgsConstructor;
import org.springframework.security.access.PermissionEvaluator;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Component;

import java.io.Serializable;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 自定义权限注解验证
 *
 * @author Wang Chinda
 * @date 2020/7/11
 * @see
 * @since 1.0
 */
@Component
@AllArgsConstructor
public class UserPermissionEvaluator implements PermissionEvaluator {

    private final SysMenuService sysMenuService;
    private final SysConfigService sysConfigService;

    /**
     * hasPermission鉴权方法
     * 这里仅仅判断PreAuthorize注解中的权限表达式
     * 实际中可以根据业务需求设计数据库通过targetUrl(一定是URL, 还可以是管理员标识等)和permission做更复杂的鉴权
     * @param authentication
     * @param targetUrl
     * @param permission
     * @return
     */
    @Override
    public boolean hasPermission(Authentication authentication, Object targetUrl, Object permission) {
        // 获取用户信息
        SysUserDetails userDetails = (SysUserDetails) authentication.getPrincipal();
        List<SysMenuEntity> sysMenuEntityList = null;
        if (ObjectUtil.equal(userDetails.getUserId(), Convert.toLong(sysConfigService.getByParamKey(CommonConstant.SUPER_ADMIN).getParamValue()))) {
            // 查询管理员权限(这里可以将权限放入缓存中提升效率)
            sysMenuEntityList = sysMenuService.list();
        } else {
            // 查询用户权限(这里可以将权限放入缓存中提升效率)
            sysMenuEntityList = sysMenuService.selectSysMenuByUserId(userDetails.getUserId());
        }
        Set<String> permissions = sysMenuEntityList.stream().map(SysMenuEntity::getPerms).collect(Collectors.toSet());
        // 权限对比
        return permissions.contains(permission.toString());
    }

    @Override
    public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType, Object permission) {
        return false;
    }
}
